home *** CD-ROM | disk | FTP | other *** search
/ Sun Solutions 1997 April to September / Sun Solutions CD - APR '97 - SEP '97 (704-3778-12 Rev. H)(Sun Microsystems, Inc.)(1997).iso / products / bin / httpd / src / http_mime.c < prev    next >
C/C++ Source or Header  |  1995-05-18  |  15KB  |  592 lines

  1. /*
  2.  * http_mime.c: Sends/gets MIME headers for requests
  3.  * 
  4.  * All code contained herein is covered by the Copyright as distributed
  5.  * in the README file in the main directory of the distribution of 
  6.  * NCSA HTTPD.
  7.  *
  8.  * Based on NCSA HTTPd 1.3 by Rob McCool
  9.  * 
  10.  * 
  11.  * 03/19/95 blong
  12.  *      Added set_stat_line as part of making user config error messages work
  13.  *      The correct status line should now be sent back
  14.  *
  15.  * 04/20/95 blong
  16.  *    Added a modified "B18" from apache patches by Rob Hartill
  17.  */
  18.  
  19.  
  20. #include "httpd.h"
  21. #include "new.h"
  22.  
  23. struct mime_ext {
  24.     char *ext;
  25.     char *ct;
  26.     struct mime_ext *next;
  27. };
  28.  
  29. #if 1
  30. #define hash(i) (isalpha(i) ? (tolower(i)) - 'a' : 26)
  31. #else
  32. #define hash(i) ((i) % 27)
  33. #endif
  34.  
  35. /* Hash table */
  36. struct mime_ext *types[27];
  37. struct mime_ext *forced_types;
  38. struct mime_ext *encoding_types;
  39. struct mime_ext *Saved_Forced;
  40. struct mime_ext *Saved_Encoding;
  41.  
  42. int content_length;
  43. char content_type[MAX_STRING_LEN];
  44. char content_encoding[MAX_STRING_LEN];
  45.  
  46. char location[MAX_STRING_LEN];
  47. static char last_modified[MAX_STRING_LEN];
  48.  
  49. char auth_line[MAX_STRING_LEN];
  50.  
  51. char *out_headers = NULL;
  52. char **in_headers_env = NULL;
  53. char *status_line = NULL;
  54. char ims[MAX_STRING_LEN]; /* If-modified-since */
  55.  
  56. extern FILE *agent_log;
  57. extern FILE *referer_log;
  58. extern char referer_ignore[MAX_STRING_LEN];
  59. char referer[HUGE_STRING_LEN];
  60.  
  61. void hash_insert(struct mime_ext *me) {
  62.     register int i = hash(me->ext[0]);
  63.     register struct mime_ext *p, *q;
  64.  
  65.     if(!(q=types[i])) {
  66.         types[i]=me;
  67.         return;
  68.     }
  69.     if((!(p=q->next)) && (strcmp(q->ext,me->ext) >= 0)) {
  70.         types[i]=me;
  71.         me->next=q;
  72.         return;
  73.     }
  74.     while(p) {
  75.         if(strcmp(p->ext,me->ext) >= 0) break;
  76.         q=p;
  77.         p=p->next;
  78.     }
  79.     me->next=p;
  80.     q->next=me;
  81. }
  82.  
  83. void kill_mime() {
  84.     register struct mime_ext *p,*q;
  85.     register int x;
  86.  
  87.     for(x=0;x<27;x++) {
  88.         p=types[x];
  89.         while(p) {
  90.             free(p->ext);
  91.             free(p->ct);
  92.             q=p;
  93.             p=p->next;
  94.             free(q);
  95.         }
  96.     }
  97.     p=forced_types;
  98.     while(p) {
  99.         free(p->ext);
  100.         free(p->ct);
  101.         q=p;
  102.         p=p->next;
  103.         free(q);
  104.     }
  105.     p=encoding_types;
  106.     while(p) {
  107.         free(p->ext);
  108.         free(p->ct);
  109.         q=p;
  110.         p=p->next;
  111.         free(q);
  112.     }
  113. }
  114.  
  115. void init_mime() {
  116.     char l[MAX_STRING_LEN],w[MAX_STRING_LEN],*ct;
  117.     FILE *f;
  118.     register struct mime_ext *me;
  119.     register int x;
  120.  
  121.     if(!(f = fopen(types_confname,"r"))) {
  122.         fprintf(stderr,"httpd: could not open mime types file %s\n",
  123.                 types_confname);
  124.         perror("fopen");
  125.         exit(1);
  126.     }
  127.  
  128.     for(x=0;x<27;x++) 
  129.         types[x] = NULL;
  130.     forced_types = NULL;
  131.     encoding_types = NULL;
  132.  
  133.     while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
  134.         if(l[0] == '#') continue;
  135.         cfg_getword(w,l);
  136.         if(!(ct = (char *)malloc(sizeof(char) * (strlen(w) + 1))))
  137.             die(NO_MEMORY,"init_mime",stderr);
  138.         strcpy(ct,w);
  139.  
  140.         while(l[0]) {
  141.             cfg_getword(w,l);
  142.             if(!(me = (struct mime_ext *)malloc(sizeof(struct mime_ext))))
  143.                 die(NO_MEMORY,"init_mime",stderr);
  144.             if(!(me->ext = (char *)malloc(sizeof(char) * (strlen(w)+1))))
  145.                 die(NO_MEMORY,"init_mime",stderr);
  146.             for(x=0;w[x];x++)
  147.                 me->ext[x] = (islower(w[x]) ? w[x] : tolower(w[x]));
  148.             me->ext[x] = '\0';
  149.             if(!(me->ct=strdup(ct)))
  150.                 die(NO_MEMORY,"init_mime",stderr);
  151.             me->next=NULL;
  152.             hash_insert(me);
  153.         }
  154.         free(ct);
  155.     }
  156.     fclose(f);
  157. }
  158.  
  159. void dump_types() {
  160.     struct mime_ext *p;
  161.     register int x;
  162.  
  163.     for(x=0;x<27;x++) {
  164.         p=types[x];
  165.         while(p) {
  166.             printf("ext %s: %s\n",p->ext,p->ct);
  167.             p=p->next;
  168.         }
  169.     }
  170.     p=forced_types;
  171.     while(p) {
  172.         printf("file %s: %s\n",p->ext,p->ct);
  173.         p=p->next;
  174.     }
  175. }
  176.  
  177. int is_content_type(char *type) {
  178.     return(!strcmp(content_type,type));
  179. }
  180.  
  181. void find_ct(char *file, int store_encoding) {
  182.     int i,l,l2;
  183.     struct mime_ext *p;
  184.     char fn[MAX_STRING_LEN];
  185.  
  186.     lim_strcpy(fn,file, MAX_STRING_LEN);
  187. /*    l = strlen(fn);
  188.     if (fn[l-1] == '/') 
  189.       fn[l-1] = '\0'; */
  190.     if((i=rind(fn,'.')) >= 0) {
  191.         ++i;
  192.         l=strlen(fn);
  193.         p = encoding_types;
  194.  
  195.         while(p) {
  196.             if(!strcmp(p->ext,&fn[i])) {
  197.                 fn[i-1] = '\0';
  198.                 if(store_encoding) {
  199.                     if(content_encoding[0])
  200.                         sprintf(content_encoding,"%s, %s",content_encoding,
  201.                                 p->ct);
  202.                     else
  203.                         strcpy(content_encoding,p->ct);
  204.                 }
  205.                 if((i=rind(fn,'.')) < 0)
  206.                     break;
  207.                 ++i;
  208.                 l=strlen(fn);
  209.                 p=encoding_types;
  210.             }
  211.             else
  212.                 p=p->next;
  213.         }
  214.     }
  215.     p=forced_types;
  216.     l=strlen(fn);
  217.  
  218.     while(p) {
  219.         l2=l-strlen(p->ext);
  220.         if((l2 >= 0) && (!strcasecmp(p->ext,&fn[l2]))) {
  221.             strcpy(content_type,p->ct);
  222.             return;
  223.         }
  224.         p=p->next;
  225.     }
  226.  
  227.     if((i = rind(fn,'.')) < 0) {
  228.     if (local_default_type[0] != '\0') 
  229.       strcpy(content_type,local_default_type);
  230.          else strcpy(content_type,default_type);
  231.         return;
  232.     }
  233.     ++i;
  234.     p=types[hash(fn[i])];
  235.  
  236.     while(p) {
  237.         if(!strcasecmp(p->ext,&fn[i])) {
  238.             strcpy(content_type,p->ct);
  239.             return;
  240.         }
  241.         p=p->next;
  242.     }
  243.     if (local_default_type[0] != '\0') 
  244.       strcpy(content_type,local_default_type);
  245.      else strcpy(content_type,default_type);
  246. }
  247.  
  248.  
  249.  
  250. void probe_content_type(char *file) {
  251.     find_ct(file,0);
  252. }
  253.  
  254. void set_content_type(char *file) {
  255.     find_ct(file,1);
  256. }
  257.  
  258. int scan_script_header(FILE *f, FILE *fd) {
  259.     char w[MAX_STRING_LEN];
  260.     char *l;
  261.     int p;
  262.  
  263.     while(1) {
  264.         if(getline(w,MAX_STRING_LEN-1,fileno(f),timeout))
  265.             die(SERVER_ERROR,"httpd: malformed header from script",fd);
  266.  
  267. /* Always return zero, so as not to cause redirect+sleep3+kill */
  268.         if(w[0] == '\0') {
  269.         if (content_type[0] == '\0') {
  270.            if (location[0] != '\0') {
  271.          strcpy(content_type,"text/html");
  272.            } else {
  273.              if (local_default_type[0] != '\0')
  274.            strcpy(content_type,local_default_type);
  275.               else strcpy(content_type,default_type);
  276.            }
  277.             }
  278.         return 0;
  279.         }                            
  280.         if(!(l = strchr(w,':')))
  281.             l = w;
  282.         *l++ = '\0';
  283.         if(!strcasecmp(w,"Content-type")) {
  284.       /* Thanks Netscape for showing this bug to everyone */
  285.       /* delete trailing whitespace, esp. for "server push" */
  286.       char *endp = l + strlen(l) - 1;
  287.       while ((endp > l) && isspace(*endp)) *endp-- = '\0';
  288.             sscanf(l,"%s",content_type);
  289.         } 
  290.         else if(!strcasecmp(w,"Location")) {
  291.     /* If we don't already have a status line, make one */
  292.         if (!&status_line[0]) {
  293.                 status = 302;
  294.                 set_stat_line();
  295.         }
  296.               sscanf(l,"%s",location);
  297.     } 
  298.         else if(!strcasecmp(w,"Status")) {
  299.             for(p=0;isspace(l[p]);p++);
  300.             sscanf(&l[p],"%d",&status);
  301.             if(!(status_line = strdup(&l[p])))
  302.                 die(NO_MEMORY,"scan_script_header",fd);
  303.         }
  304.         else {
  305.             *(--l) = ':';
  306.             for(p=0;w[p];p++);
  307.             w[p] = LF;
  308.             w[++p] = '\0';
  309.             if(!out_headers) {
  310.                 if(!(out_headers = strdup(w)))
  311.                     die(NO_MEMORY,"scan_script_header",fd);
  312.             }
  313.             else {
  314.                 int loh = strlen(out_headers);
  315.                 out_headers = (char *) realloc(out_headers,
  316.                                                (loh+strlen(w)+1)*sizeof(char));
  317.                 if(!out_headers)
  318.                     die(NO_MEMORY,"scan_script_header",fd);
  319.                 strcpy(&out_headers[loh],w);
  320.             }
  321.         }
  322.     }
  323. }
  324.  
  325.  
  326.  
  327. /* Should remove all the added types from .htaccess files when the 
  328.    child sticks around */
  329.  
  330. void reset_mime_vars() {
  331.   struct mime_ext *mimes,*tmp;
  332.  
  333.   mimes = forced_types;
  334.   tmp = mimes;
  335.   while (mimes != Saved_Forced) {
  336.     mimes = mimes->next;
  337.     free(tmp->ext);
  338.     free(tmp->ct);
  339.     free(tmp);
  340.     tmp = mimes;
  341.   }
  342.  
  343.   forced_types = Saved_Forced;
  344.  
  345.   mimes = encoding_types;
  346.   tmp = mimes;
  347.  
  348.   while (mimes != Saved_Encoding) {
  349.     mimes = mimes->next;
  350.     free(tmp->ext);
  351.     free(tmp->ct);
  352.     free(tmp);
  353.     tmp = mimes;
  354.   }
  355.  
  356.   encoding_types = Saved_Encoding;
  357. }
  358.  
  359. void add_type(char *fn, char *t, FILE *out) {
  360.     struct mime_ext *n;
  361.  
  362.     if(!(n=(struct mime_ext *)malloc(sizeof(struct mime_ext))))
  363.         die(NO_MEMORY,"add_type",out);
  364.  
  365.     if(!(n->ext = strdup(fn)))
  366.         die(NO_MEMORY,"add_type",out);
  367.     if(!(n->ct = strdup(t)))
  368.         die(NO_MEMORY,"add_type",out);
  369.     n->next = forced_types;
  370.     forced_types = n;
  371. }
  372.  
  373. void add_encoding(char *fn, char *t,FILE *out) {
  374.     struct mime_ext *n;
  375.  
  376.     if(!(n=(struct mime_ext *)malloc(sizeof(struct mime_ext))))
  377.         die(NO_MEMORY,"add_encoding",out);
  378.  
  379.     if(!(n->ext = strdup(fn)))
  380.         die(NO_MEMORY,"add_encoding",out);
  381.     if(!(n->ct = strdup(t)))
  382.         die(NO_MEMORY,"add_encoding",out);
  383.     n->next = encoding_types;
  384.     encoding_types = n;
  385. }
  386.  
  387. void set_content_length(int l) {
  388.     content_length = l;
  389. }
  390.  
  391. int set_last_modified(time_t t, FILE *out) {
  392.     struct tm *tms;
  393.     char ts[MAX_STRING_LEN];
  394.  
  395.     tms = gmtime(&t);
  396.     strftime(ts,MAX_STRING_LEN,HTTP_TIME_FORMAT,tms);
  397.     strcpy(last_modified,ts);
  398.  
  399.     if(!ims[0])
  400.         return 0;
  401.  
  402.     if(later_than(tms, ims))
  403.         return die(USE_LOCAL_COPY,NULL,out);
  404.  
  405.     return 0;
  406. }
  407.  
  408. void init_header_vars() 
  409. {
  410.     referer[0] = '\0';
  411.     content_type[0] = '\0';
  412.     last_modified[0] = '\0';
  413.     content_length = -1;
  414.     auth_line[0] = '\0';
  415.     content_encoding[0] = '\0';
  416.     location[0] = '\0';
  417.     ims[0] = '\0';
  418.     if (status_line != NULL) free(status_line);
  419.     status_line = NULL;
  420.     if (out_headers != NULL) free(out_headers);
  421.     out_headers = NULL;
  422.  
  423.     if (in_headers_env != NULL) {
  424.        free_env(in_headers_env);
  425.        in_headers_env = NULL;
  426.     } 
  427.     
  428. }
  429.  
  430. int merge_header(char *h, char *v, FILE *out) {
  431.     register int l,lt;
  432.     char **t;
  433.  
  434.     for(l=0;h[l];++l);
  435.     h[l] = '=';
  436.     h[++l] = '\0';
  437.  
  438.     for(t=in_headers_env;*t;++t) {
  439.         if(!strncmp(*t,h,l)) {
  440.             lt = strlen(*t);
  441.             if(!(*t = (char *) realloc(*t,(lt+strlen(v)+3)*sizeof(char))))
  442.                 die(NO_MEMORY,"merge_header",out);
  443.             (*t)[lt++] = ',';
  444.             (*t)[lt++] = ' ';
  445.             strcpy(&((*t)[lt]),v);
  446.             return 1;
  447.         }
  448.     }
  449.     h[l-1] = '\0';
  450.     return 0;
  451. }
  452.  
  453. void get_mime_headers(int fd, FILE *out, char* url) {
  454.     char w[MAX_STRING_LEN];
  455.     char l[MAX_STRING_LEN];
  456.     int num_inh, num_processed;
  457.     char *t;
  458.  
  459.     num_inh = 0;
  460.     num_processed = 0;
  461.  
  462.     while(!(getline(w,MAX_STRING_LEN-1,fd,timeout))) {
  463.         if(!w[0]) 
  464.             return;
  465.         if((++num_processed) > MAX_HEADERS)
  466.             die(BAD_REQUEST,"too many header lines",out);
  467.         if(!(t = strchr(w,':')))
  468.             continue;
  469.         *t++ = '\0';
  470.         while(isspace(*t)) ++t;
  471.         strcpy(l,t);
  472.  
  473.         if(!strcasecmp(w,"Content-type")) {
  474.             strcpy(content_type,l);
  475.             continue;
  476.         }
  477.         if(!strcasecmp(w,"Authorization")) {
  478.             strcpy(auth_line,l);
  479.             continue;
  480.         }
  481.         if(!strcasecmp(w,"Content-length")) {
  482.             sscanf(l,"%d",&content_length);
  483.             continue;
  484.         }
  485.         if(!strcasecmp(w,"User-agent")) {
  486.             fprintf(agent_log, "%s\n", l);
  487.         fflush(agent_log);
  488.         }
  489.         if(!strcasecmp(w,"Referer")) {
  490.         strcpy(referer,l);
  491.         if ((!strlen(referer_ignore)) || (!strstr(l,referer_ignore))){
  492.         fprintf(referer_log, "%s -> %s\n", l, url);
  493.         fflush(referer_log);
  494.         }
  495.         }
  496.         if(!strcasecmp(w,"If-modified-since"))
  497.             strcpy(ims,l);
  498.  
  499.         http2cgi(w);
  500.         if(in_headers_env) {
  501.             if(!merge_header(w,l,out)) {
  502.                 in_headers_env = 
  503.                     (char **) realloc(in_headers_env,
  504.                                       (num_inh+2)*sizeof(char *));
  505.                 if(!in_headers_env)
  506.                     die(NO_MEMORY,"get_mime_headers",out);
  507.                 in_headers_env[num_inh++] = make_env_str(w,l,out);
  508.                 in_headers_env[num_inh] = NULL;
  509.             }
  510.         }
  511.         else {
  512.             if(!(in_headers_env = (char **) malloc(2*sizeof(char *))))
  513.                 die(NO_MEMORY,"get_mime_headers",out);
  514.             in_headers_env[num_inh++] = make_env_str(w,l,out);
  515.             in_headers_env[num_inh] = NULL;
  516.         }
  517.     }
  518. }
  519.  
  520.  
  521. void dump_default_header(FILE *fd) {
  522.     fprintf(fd,"Date: %s%c",gm_timestr_822(time(NULL)),LF);
  523.     fprintf(fd,"Server: %s%c",SERVER_VERSION,LF);
  524.    
  525.     if (annotation_server[0])
  526.     fprintf(fd,"Annotations-cgi: %s%c",annotation_server,LF);
  527.  
  528. /* Not part of HTTP spec, removed. */
  529. /*    fprintf(fd,"MIME-version: 1.0%c",LF); */
  530. }
  531.  
  532. char* set_stat_line() {
  533.     if (status_line) free(status_line);
  534.     switch (status) {
  535.     case 302:
  536.     status_line = strdup((char *)StatLine302);
  537.     break;
  538.     case 304:
  539.     status_line = strdup((char *)StatLine304);
  540.     break;
  541.     case 400:
  542.     status_line = strdup((char *)StatLine400);
  543.     break;
  544.     case 401:
  545.     status_line = strdup((char *)StatLine401);
  546.     break;
  547.     case 403:
  548.     status_line = strdup((char *)StatLine403);
  549.     break;
  550.     case 404:
  551.     status_line = strdup((char *)StatLine404);
  552.     break;
  553.     case 500:
  554.     status_line = strdup((char *)StatLine500);
  555.     break;
  556.     case 501:
  557.     status_line = strdup((char *)StatLine501);
  558.     break;
  559.     default:
  560.     status_line = strdup((char *)StatLine200);
  561.     break;
  562.     }
  563.     return status_line;
  564. }
  565.     
  566. void send_http_header(FILE *fd) {
  567.     if(!status_line) {
  568.         if(location[0]) {
  569.             status = 302;
  570.         status_line = strdup((char *)StatLine302);
  571.         }
  572.         else {
  573.         set_stat_line();
  574.         }
  575.     }            
  576.     begin_http_header(fd,status_line);
  577.     if(content_type[0])
  578.         fprintf(fd,"Content-type: %s%c",content_type,LF);
  579.     if(last_modified[0])
  580.         fprintf(fd,"Last-modified: %s%c",last_modified,LF);
  581.     if(content_length >= 0) 
  582.         fprintf(fd,"Content-length: %d%c",content_length,LF);
  583.     if(location[0])
  584.         fprintf(fd,"Location: %s%c",location,LF);
  585.     if(content_encoding[0])
  586.         fprintf(fd,"Content-encoding: %s%c",content_encoding,LF);
  587.     if(out_headers)
  588.         fprintf(fd,"%s",out_headers);
  589.     fprintf(fd,"%c",LF);
  590.     fflush(fd);
  591. }
  592.